package com.health.trans.pojo;

import cn.hutool.core.util.RandomUtil;
import com.health.trans.processor.listener.JobEndListener;
import com.health.trans.processor.listener.MyItemReadListener;
import com.health.trans.processor.listener.StepItemWriteListener;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.beans.BeanUtils;

import java.util.Date;
import java.util.Objects;
import java.util.concurrent.atomic.LongAdder;
import java.util.function.Function;

/**
 * @author nqlz
 */
@Getter
@Setter
@Accessors(chain = true)
@Slf4j
@AllArgsConstructor
@ToString
public class JobConfig<T> {

    /**
     * 符合条件数量
     */
    private Long queryCount;
    /**
     * 全局 所有已处理 数据数量
     */
    private LongAdder allDoneCount;

    private int chunkSize;

    /**
     * 自定义 最高发送数量
     */
    private Long maxCount;
    /**
     * 任务总数
     */
    private int totalTask;
    /**
     * 当前任务
     */
    private int taskIndex;
    /**
     * 任务 数据发送数量
     */
    private Long taskCount;

    /**
     * 当前 任务已发送数量
     */
    private LongAdder taskDoneCount = new LongAdder();

    private String readResource;
    private String writerResource;

    /**
     * 数据库,默认为 platform_standard
     */
    private String dataBaseName;

    /**
     * SQL
     */
    private String sql = "";

    private final Class<T> writeTableClass;
    private final Class<T> readTableClass;
    private String readTableName;
    private String tableName;
    private String optimizedFieldName;

    private String transType;
    private TableInfo<T> tableInfo;

    private JobEndListener jobEndListener = new JobEndListener() {
        @Override
        public void afterJob(JobExecution jobExecution) {
            log.info("子任务 {} 已完成，耗时：{},taskCount：{}", taskIndex + "/" + totalTask, this.getTime(), taskCount);
        }
    };

    public String getLog() {

        String to = Objects.nonNull(writeTableClass) ? writeTableClass.getSimpleName() : "";
        long finalCount = maxCount > 0 ? maxCount : queryCount;

        return " 从 " + readResource + "发往" + tableInfo.getWriterConfig().getSourceName() + "  -" + to + "已发:"
                + " 任务" + taskIndex + "/" + totalTask + ":" + taskDoneCount.longValue() + "/" + taskCount + ""
                + "/总进度：" + allDoneCount.longValue() + "/" + finalCount;

    }

    private JobInit<T> jobInit;

    public void log(int size) {
        synchronized (Thread.currentThread().getName().intern()) {
            taskDoneCount.add(size);
            allDoneCount.add(size);
            log.info("\n");
            log.info(getLog());
            MyItemReadListener.dateInfoLocal.get().printLog();
            StepItemWriteListener.dateInfoLocal.get().printLog();
        }
    }

    private JobConfig(Class<T> writeTableClass, Class<T> readTableClass) {
        this.writeTableClass = writeTableClass;
        this.readTableClass = readTableClass;
    }

    public static <T> JobConfig<T> getInstance(TableInfo<T> tableInfo, TransParam param) {
        ReaderJson reader = param.getReader();
        WriterJson writer = param.getWriter();
        JobConfig<T> jobConfig = new JobConfig<>(tableInfo.getWriterTableClass(), tableInfo.getReadTableClass());
        BeanUtils.copyProperties(reader, jobConfig);
        jobConfig.setReadResource(reader.getSource());
        jobConfig.setWriterResource(writer.getSource());
        jobConfig.setTableInfo(tableInfo);
        String jobName = Objects.isNull(tableInfo.getReadTableClass()) ? "job-" + RandomUtil.randomInt() : tableInfo.getReadTableClass().getSimpleName();
        jobConfig.setReadTableName(tableInfo.getReadTableName());
        jobConfig.jobInit = new JobInit<>(jobConfig.getChunkSize(), jobName);
        jobConfig.jobInit.setEndListener(jobConfig.getJobEndListener());
        return jobConfig;
    }

    public JobConfig<T> setSql(String sql) {
        this.sql = sql;
        return this;
    }


    public void initJobStep(Function<StepBuilder, StepBuilder> stepSupplier) {
        jobInit.initStep(stepSupplier);
    }

    public void initJobBuilder(Function<JobBuilder, JobBuilder> jobBuilderFunction) {
        jobInit.initJob(jobBuilderFunction);
    }

    /**
     * 初始化itemReader，默认为JdbcReader
     *
     * @param reader 读者
     * @return {@link JobConfig}<{@link T}>
     */
    public JobConfig<T> initReader(ItemReader<T> reader) {
        jobInit.setReader(reader);
        return this;
    }

    public JobConfig<T> initWriter(ItemWriter<T> itemWriter) {
        jobInit.setWriter(itemWriter);
        return this;
    }

    public JobConfig<T> initProcessor(ItemProcessor<T, ?> itemProcessor) {
        jobInit.setItemProcessor(itemProcessor);
        return this;
    }

}
